﻿using System;
using UnityEngine;
using UnityEngine.UI;

public abstract class GridScrollListCreator : BaseScrollListCreator
{
    public override Vector2 Spacing => layout.spacing;

    protected GridLayoutGroup layout;
    protected int cellCountX = 1;
    protected int cellCountY = 1;
    protected abstract int ConstraintCount { get; }

    public override void Init(ScrollRectEx tool, IScrollList scrollList)
    {
        base.Init(tool, scrollList);
        layout = base.tool.content.GetComponent<GridLayoutGroup>();
        CalculateCellCount();
    }

    protected abstract void RecycleBegin();

    protected abstract void RecycleEnd();

    protected abstract RectTransform NewNext(int createIndex);

    protected abstract RectTransform NewBefore(int createIndex);

    public abstract bool IsCanRecycleBegin();

    public abstract bool IsCanRecycleEnd();

    public override bool TryCreateBefore(out RectTransform item, CreatorTool? tool)
    {
        item = null;

        var createIndex = 0;
        if (tool != null)
        {
            createIndex = GetScrollCreateIndex(tool.Value);
            if (createIndex >= ConstraintCount)
                return false;
        }

        if (!IsNeedCreateBefore())
            return false;

        item = GetItem(RecycleType.Before, createIndex);

        UpdateActiveList();

        return true;
    }

    public override bool TryCreateNext(out RectTransform item, CreatorTool? tool)
    {
        item = null;

        var createIndex = 0;
        if (tool != null)
        {
            createIndex = GetScrollCreateIndex(tool.Value);
            if (createIndex >= ConstraintCount)
                return false;
        }

        if (!IsNeedCreateNext())
            return false;

        item = GetItem(RecycleType.Next, createIndex);

        UpdateActiveList();

        return true;
    }

    private int GetScrollCreateIndex(CreatorTool tool)
    {
        if (tool.createType == CreatorTool.CreateType.Scroll)
            return tool.createIndex;

        return 0;
    }

    public override bool TryGetItemByChildIndex(int childIndex, out RectTransform item)
    {
        item = null;

        if (childIndex >= activeList.Count || childIndex < 0)
            return false;

        item = activeList[childIndex];
        return true;
    }

    public override bool TryInsertItem(int childIndex, out RectTransform item)
    {
        item = null;

        if (childIndex < 0)
        {
            item = GetItem(RecycleType.Before, 0);
            m_lastItemChange(1);
        }
        else
        {
            if (childIndex >= activeList.Count || childIndex < 0)
                return false;

            if (IsCanRecycleEnd())
                RecycleEnd();

            item = GetItem(RecycleType.Next, 0);

            var unactivatedCount = GetUnactivatedCount(childIndex);
            var itemIndex = childIndex + unactivatedCount;

            item.SetSiblingIndex(itemIndex);
        }

        UpdateActiveList();

        return true;
    }

    public override void TryRemoveItem(int childIndex)
    {
        if (childIndex < 0)
        {
            RecycleItem(0, activeList[0]);
        }
        else
        {
            if (childIndex >= activeList.Count || childIndex < 0)
                return;

            RecycleItem(childIndex, activeList[childIndex]);
        }

        m_lastItemChange(-1);
        UpdateActiveList();
    }

    public override void OnViewBoundsChange()
    {
        CalculateCellCount();
    }

    protected void CalculateCellCount()
    {
        var rectTransform = tool.viewRect;
        var m_Constraint = layout.constraint;
        var m_ConstraintCount = layout.constraintCount;
        var padding = layout.padding;
        var spacing = layout.spacing;
        var cellSize = layout.cellSize;
        var rectChildren = activeList;

        float width = rectTransform.rect.size.x;
        float height = rectTransform.rect.size.y;

        if (m_Constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            cellCountX = m_ConstraintCount;

            if (rectChildren.Count > cellCountX)
                cellCountY = rectChildren.Count / cellCountX + (rectChildren.Count % cellCountX > 0 ? 1 : 0);
        }
        else if (m_Constraint == GridLayoutGroup.Constraint.FixedRowCount)
        {
            cellCountY = m_ConstraintCount;

            if (rectChildren.Count > cellCountY)
                cellCountX = rectChildren.Count / cellCountY + (rectChildren.Count % cellCountY > 0 ? 1 : 0);
        }
        else
        {
            if (cellSize.x + spacing.x <= 0)
                cellCountX = int.MaxValue;
            else
                cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));

            if (cellSize.y + spacing.y <= 0)
                cellCountY = int.MaxValue;
            else
                cellCountY = Mathf.Max(1, Mathf.FloorToInt((height - padding.vertical + spacing.y + 0.001f) / (cellSize.y + spacing.y)));
        }
    }

    private RectTransform GetItem(RecycleType type, int createIndex)
    {
        switch (type)
        {
            case RecycleType.Next:
                return NewNext(createIndex);

            case RecycleType.Before:
                return NewBefore(createIndex);
        }
        return null;
    }

    public enum RecycleType
    {
        /// <summary>
        /// 不需要创建
        /// </summary>
        None,
        /// <summary>
        /// 添加到末尾
        /// </summary>
        Next,
        /// <summary>
        /// 添加到开头
        /// </summary>
        Before,
    }
}